//
// Created by tacom on 2024/9/23.
//

/***
 * PICO
     * PICO_DEFAULT_SPI 0
     * PICO_DEFAULT_SPI_SCK_PIN 18 -> pin 24
     * PICO_DEFAULT_SPI_TX_PIN 19 -> pin 25
     * PICO_DEFAULT_SPI_RX_PIN 16 -> pin 21
     * PICO_DEFAULT_SPI_CSN_PIN 17 -> pin 22
 * HUAIWEI
     * SPI0_SCK: GPIO2_25(Pin 89, wPi 14), number 23
     * SPI0_MISO: GPIO2_28(Pin 92, wPi 12), number 21
     * SPI0_MOSI:GPIO2_27(Pin 91, wPi 11), number 19
     * SPI0_CS: GPIO2_26(Pin 90, wPi 15), number 24
     * linux device: /dev/spidev0.0
 * 问题:
     * 收发固定长度的数据，需要自行组织合适长度的通信协议
     * https://forums.raspberrypi.com/viewtopic.php?p=2250236&hilit=pico+spi+slave#p2250236
     * 注意将运行模式设定为3，从而完成收发确认
 */

#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include "string.h"
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/uart.h"
#include "hardware/spi.h"

/**  protocol config    **/
// uart
#define UART_ID uart0
#define UART_RATE 115200
#define UART_TX_PIN 0
#define UART_RX_PIN 1
static char uart_buffer[256];

// spi buffer
#define BUF_LEN         0x100
static uint8_t out_buf[BUF_LEN], in_buf[BUF_LEN];

// led status
static bool LED_STATUS = true;

// print to uart
void print_to_uart(const char *format, ...){
    va_list args;
    va_start(args, format);

    memset(uart_buffer, 0, 256);
    int len = vsnprintf(uart_buffer, 256, format, args);
    va_end(args);

    //uart_puts(UART_ID, uart_buffer);
    uart_write_blocking(UART_ID, (uint8_t *)uart_buffer, len);
}

void blink_led(){
    gpio_put(PICO_DEFAULT_LED_PIN, LED_STATUS);
    LED_STATUS = !LED_STATUS;
}

void clean_buffer_data(){
    for (size_t i = 0; i < BUF_LEN; ++i) {
        // bit-inverted from i. The values should be: {0xff, 0xfe, 0xfd...}
        in_buf[i] = 0;
        if(i < 8){
            out_buf[i] = i;
        }
    }
}


void printbuf(uint8_t buf[], size_t len) {
    size_t i;
    for (i = 0; i < len; ++i) {
        if (i % 16 == 15)
            print_to_uart("%02x\r\n", buf[i]);
        else
            print_to_uart("%02x ", buf[i]);
    }

    // append trailing newline if there isn't one
    if (i % 16) {
        print_to_uart("\r\n");
    }
}

//int __not_in_flash_func(spi_write_read_blocking_)(spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len) {
//    invalid_params_if(HARDWARE_SPI, 0 > (int)len);
//
//    // Never have more transfers in flight than will fit into the RX FIFO,
//    // else FIFO will overflow if this code is heavily interrupted.
//    const size_t fifo_depth = 8;
//    size_t rx_remaining = len, tx_remaining = len;
//
//    while (rx_remaining || tx_remaining) {
//        if (tx_remaining && spi_is_writable(spi) && rx_remaining < tx_remaining + fifo_depth) {
//            spi_get_hw(spi)->dr = (uint32_t) *src++;
//            --tx_remaining;
//            print_to_uart("SPI Send %d %d\r\n", *(src - 1), tx_remaining);
//        }
//        if (rx_remaining && spi_is_readable(spi)) {
//            *dst++ = (uint8_t) spi_get_hw(spi)->dr;
//            --rx_remaining;
//            print_to_uart("SPI Read %d %d\r\n", *(dst - 1), rx_remaining);
//        }
//    }
//
//    return (int)len;
//}

int main() {
    // enable USB as uart
    // stdio_init_all();

    // enable uart
    uart_init(UART_ID, UART_RATE);
    gpio_set_function(UART_TX_PIN, UART_FUNCSEL_NUM(UART_ID, UART_TX_PIN));
    gpio_set_function(UART_RX_PIN, UART_FUNCSEL_NUM(UART_ID, UART_RX_PIN));

    // enable led
    gpio_init(PICO_DEFAULT_LED_PIN);
    gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
    print_to_uart("Init led done\r\n");

    // enable spi
    // SPI0 with 1Mb
    spi_init(spi_default, 1000 * 1000);
    spi_set_slave(spi_default, true);
    spi_set_format(spi_default, 8, SPI_CPOL_1, SPI_CPHA_1, SPI_MSB_FIRST);
    gpio_set_function(PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI);
    gpio_set_function(PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI);
    gpio_set_function(PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI);
    gpio_set_function(PICO_DEFAULT_SPI_CSN_PIN, GPIO_FUNC_SPI);
    print_to_uart( "Set SPI Done\r\n");

    // main
    print_to_uart( "Waiting data from host\r\n");
    size_t i = 0;
    while (true){
        // buffer clean
        clean_buffer_data();

        // debug
        print_to_uart("SPI Start Recv Pack index is: %d\r\n", i);

        // recv
         spi_write_read_blocking(spi_default, out_buf, in_buf, 8);
//        spi_read_blocking(spi_default, 100, in_buf, 1);

        // debug
        print_to_uart("SPI Recv Pack index: %d\r\n", i);

        // debug recv msg
        printbuf(in_buf, BUF_LEN);

        // debug
        blink_led();
        ++i;
    }
}